import yaml
import json
import settings
import re
from common.reflection import __reflect_module_attribute__


class _YamlData(dict):
    def __init__(self, file_path, data, section="根"):
        super().__init__(**data)
        self._file_path = file_path
        self._section = section

    def __getitem__(self, item: str):
        try:
            obj = super().__getitem__(item)
        except KeyError:
            raise LookupError("yaml文件 %s 的 %s 节点没有 %s 的配置项" % (
                self._file_path, self._section, item
            )) from None
        else:
            return self._instance(obj, item)

    def _instance(self, obj, item):
        match obj:
            case dict():
                return _YamlData(self._file_path, obj, item)
            case list():
                return [self._instance(o, item) for o in obj]
            case str():
                return obj
            case _:
                raise TypeError(f"{self._file_path}中{self._section}节点{obj}类型只能是dict、list、str中的一种")


def load_yaml(file_path):
    try:
        with open(file_path, "r", encoding="utf8") as f:
            data = yaml.load(stream=f, Loader=yaml.FullLoader)
    except FileNotFoundError:
        raise FileNotFoundError(f"元素路径 {file_path} 不存在") from None

    json_str = json.dumps(data, ensure_ascii=False)
    while True:
        if ret := re.search(settings.QUOTE_FMT, json_str):
            func_body, func_name, func_params = ret.group(
                settings.FUN_BODY,
                settings.FUNC_NAME,
                settings.FUNC_PARAMS
            )  # type: str, str, str

            try:
                val = __reflect_module_attribute__(func_body)
            except NameError:
                raise NameError(f"{file_path} 中函数名称 {func_name} 未定义") from None
            except SyntaxError:
                raise SyntaxError(f"{file_path} 中函数 {func_name} 语法不正确, 参数{func_body}") from None
            except Exception:
                raise

            match val:
                case dict() | list() | int() | float():
                    json_str = re.sub(f"\"{settings.QUOTE_FMT}\"", json.dumps(val), json_str, 1)
                case str():
                    json_str = re.sub(settings.QUOTE_FMT, val, json_str, 1)
                case _:
                    raise TypeError(f"函数 {func_name} 返回值的类型只能是 str, int, float, dict, list 中的一种")
        else:
            break
    return _YamlData(file_path, json.loads(json_str))
